﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace FluentParser.Editor
{
    [DebuggerDisplay("[TypeDescriptor {Name}]")]
    public class TypeDescriptor
    {
        public TypeDescriptor(Type source)
        {
            Source = source;
            Name = source.Name;
            GenericTypes = new List<TypeDescriptor>();
        }

        public List<TypeDescriptor> GenericTypes { get; private set; }
        public Type Source { get; private set; }
        public string Name { get; private set; }

        private void Init()
        {
            if (Source.IsGenericType)
            {
                StringBuilder sb = new StringBuilder();

                foreach (Type genericType in Source.GetGenericArguments())
                {
                    TypeDescriptor descriptor = From(genericType);
                    GenericTypes.Add(descriptor);

                    if (sb.Length > 0)
                        sb.Append(", ");
                    sb.Append(descriptor.Name);
                }

                Name = String.Concat(Name.Substring(0, Name.IndexOf('`')), "<", sb.ToString(), ">");
            }
        }

        private static readonly Dictionary<Type, TypeDescriptor> _cache = new Dictionary<Type, TypeDescriptor>();
        private static TypeDescriptor Add(Type source, string suggestedName)
        {
            TypeDescriptor descriptor = new TypeDescriptor(source);
            if (suggestedName != null)
                descriptor.Name = suggestedName;

            _cache.Add(source, descriptor);
            descriptor.Init();

            if (suggestedName != null)
                descriptor.Name = suggestedName;

            return descriptor;
        }

        public static TypeDescriptor From(Type source)
        {
            TypeDescriptor descriptor;
            if (!_cache.TryGetValue(source, out descriptor))
                descriptor = Add(source, null);

            return descriptor;
        }

        static TypeDescriptor()
        {
            Add(typeof(object), "object");
            Add(typeof(int), "int");
            Add(typeof(long), "long");
            Add(typeof(float), "float");
            Add(typeof(double), "double");
            Add(typeof(decimal), "decimal");
            Add(typeof(bool), "bool");
            Add(typeof(string), "string");
        }
    }
}
